<?php
/**
 * Class represents records from table newsletter_user_subscription
 * {autogenerated}
 * @property int $subscription_id
 * @property int $user_id
 * @property int $list_id
 * @property string $type enum('auto','user','unsubscribed')
 * @property int $is_active
 * @see Am_Table
 */
class NewsletterUserSubscription extends Am_Record
{
    /** user subscribed automatically to this subscription */
    const TYPE_AUTO = 'auto';
    /** user specially agreed to receive this list */
    const TYPE_USER = 'user';
    /** user specially decied to unsubscribe from this list */
    const TYPE_UNSUBSCRIBED = 'unsubscribed';

    protected $_user;

    function enable($type = null, $throwExceptions=false)
    {
        if ($type !== null)
            $this->updateQuick('type', $type);
        try {
            if (!$this->is_active)
                if (!$this->getList()->getPlugin()->changeSubscription($this->getUser(),
                                [$this->getList()->plugin_list_id], [],
                        (!empty($this->begin_date) ?
                        [$this->getList()->plugin_list_id => ['begin_date' => $this->begin_date, 'expire_date' => $this->expire_date]] : [])))
                    return $this; // do not update if call failed (!)
        } catch (Exception $e) {
            $this->getDi()->logger->error("EXCEPTION during subscribe user $this->user_id to list $this->list_id");
            $this->getDi()->logger->error($e);

            if($throwExceptions)
                throw $e;

            return $this;
        }
        $this->updateQuick('is_active', 1);
        return $this;
    }
    function disable($throwExceptions=false)
    {
        try {
            if ($this->is_active)
            {
                try
                {
                    $pl = $this->getList()->getPlugin();
                } catch (Exception $e) {
                    //plugin was disabled
                    $this->updateQuick('is_active', 0);
                    return $this;
                }
                if (!$pl->changeSubscription($this->getUser(), [], [$this->getList()->plugin_list_id]))
                    return $this; // do not update active flag if failed (!)
            }
        } catch (Exception $e) {
            $this->getDi()->logger->error("EXCEPTION during unsubscribe user $this->user_id from list $this->list_id");
            $this->getDi()->logger->error($e);

            if($throwExceptions)
                throw $e;

            return $this;
        }
        $this->updateQuick('is_active', 0);
        try {
            $event = new Am_Event(Bootstrap_Newsletter::NEWSLETTER_LIST_SUBSCRIPTION_REMOVED, ['user' => $this->getUser(), 'list' => $this->getList()]);
            $this->getDi()->hook->call($event);
        }
        catch(Am_Exception_Db_NotFound $e)
        {
            $this->getDi()->errorLogTable->logException($e);
        }
        return $this;
    }
    /** @return NewsletterList */
    function getList()
    {
        return $this->getDi()->newsletterListTable->load($this->list_id);
    }
    function getUser()
    {
        if (!$this->_user)
            $this->_user = $this->getDi()->userTable->load($this->user_id);
        return $this->_user;
    }
    function _setUser(User $user)
    {
        $this->_user = $user;
    }
    function unsubscribe($throwExceptions=false)
    {
        $this->disable($throwExceptions);
        $this->updateQuick('type', self::TYPE_UNSUBSCRIBED);
        return $this;
    }
    function isUnsubscribed()
    {
        return $this->type == self::TYPE_UNSUBSCRIBED;
    }
    function delete($throwExceptions=false)
    {
        $this->disable($throwExceptions);
        parent::delete();
    }
}

class NewsletterUserSubscriptionTable extends Am_Table
{
    protected $_key = 'subscription_id';
    protected $_table = '?_newsletter_user_subscription';

    /**
     * Add or enable subscription
     * @param type $user_id
     * @param type $list_id
     * @param type $type
     * @return type
     */
    function add(User $user, NewsletterList $list, $type)
    {
        $list_id = $list->pk();
        $user_id = $user->pk();
        $sub = $this->findFirstBy([
            'user_id' => $user_id,
            'list_id' => $list_id,
        ]);
        if (!$sub) {
            $sub = $this->createRecord();
            $sub->user_id = $user_id;
            $sub->list_id = $list_id;
            $sub->is_active = 0;
            $sub->insert();
        }
        if(!empty($list->begin_date))
        {
            $sub->begin_date = $list->begin_date;
            $sub->expire_date = $list->expire_date;
        }
        $sub->enable($type);
        return $sub;
    }
    function checkSubscriptions(User $user)
    {
        if (!empty($user->unsubscribed))
        {
            foreach($this->findByUserId($user->pk()) as $sub) {
                $sub->unsubscribe();
            }
            return;
        }

        // array of NewsletterList user has access at all
        $ids = [];

        foreach ($this->getDi()->newsletterListTable->getAllowed($user) as $list)
        {
            $ids[ $list->pk() ] = ['l' => $list];
        }
        foreach ($this->findByUserId($user->pk()) as $r)
        {
            $ids[ $r->list_id]['s'] = $r;
        }

        ////
        foreach ($ids as $list_id => $record)
        {
            /* @var $availableList NewsletterList */
            if (empty($record['l'])) $record['l'] = null;
            if (empty($record['s'])) $record['s'] = null;
            $availableList = $record['l'];
            /* @var $existingSub NewsletterUserSubscription */
            $existingSub = $record['s'];

            if ($existingSub)
            {
                if (!$availableList)
                {
                    // if not available now, de-activate
                    $existingSub->disable();
                    continue;
                } elseif ($existingSub->isUnsubscribed()) {
                    // if user unsubscribed previously, make sure it disabled
                    $existingSub->disable();
                    continue;
                } else  { // status = user or status = auto
                    // if user was subscribed before, enable it
                    $existingSub->enable();
                }
            } elseif ($user->data()->get(Bootstrap_Newsletter::NEWSLETTER_SIGNUP_DATA) == 1) {
                $this->add($user, $availableList, NewsletterUserSubscription::TYPE_USER);
            } elseif (($data = $user->data()->get(Bootstrap_Newsletter::NEWSLETTER_SIGNUP_DATA)) &&
                !empty($data[$availableList->pk()])) {
                $this->add($user, $availableList, NewsletterUserSubscription::TYPE_USER);
            } elseif ($availableList && $availableList->auto_subscribe) { // no existing list - create if 'auto'
                $this->add($user, $availableList, NewsletterUserSubscription::TYPE_AUTO);
            }
        }
    }
    /**
     * Return ids of lists user is enabled to receive, even if currently subscription is not available
     * (say subscription expired)
     * @param type $user_id
     * @return type
     */
    function getSubscribedIds($user_id)
    {
        return $this->_db->selectCol("SELECT list_id FROM $this->_table WHERE user_id=?d AND type <> ? AND is_active > 0", $user_id,
            NewsletterUserSubscription::TYPE_UNSUBSCRIBED);
    }

    /**
     * Update list of subscriptions by admin - it does not check any permissions
     * immediately, but subscriptions may be deleted during @link checkSubscriptions()
     */
    function adminSetIds($user_id, array $ids)
    {
        $user = $this->getDi()->userTable->load($user_id);
        $ids = array_filter(array_map('intval', $ids));
        $setSubs = [];
        foreach ($ids as $i)
            if ($i > 0)
            $setSubs[(int)$i] = [];

        $enabled = $disabled = [];
        foreach ($this->findByUserId($user_id) as $r)
            if ($r->is_active)
                $enabled[$r->list_id] = $r;
            else
                $disabled[$r->list_id] = $r;

        foreach (array_diff_key($enabled, $setSubs, $disabled) as $list_id => $sub)
        {
            if (!$sub->is_active) continue;
            $sub->_setUser($user);
            $sub->delete();
        }
        //
        foreach (array_diff_key($setSubs, $enabled) as $list_id => $sub)
        {
            $list = $this->getDi()->newsletterListTable->load($list_id);
            $this->add($user, $list, NewsletterUserSubscription::TYPE_AUTO);
        }
        // enable disable subscriptions
        foreach (array_intersect_key($disabled, $setSubs) as $list_id => $sub)
        {
            $sub->enable();
        }
    }
}